package multi_thread.master.executors;

import multi_thread.train.BigNumberSum;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/**
 * @author Cheng Jun
 * Description: 利用 forkjoin的分而治之思想，对 大数 求和
 * 先 fork，再 join
 * 先 拆分，再 合并结果
 * @version 1.0
 * @date 2022/5/22 20:50
 * @see BigNumberSum 几种大数求和的方法比较
 */
public class ForkJoinExample {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        long startMilli = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        SumRecTask sumRecTask = new SumRecTask(0, 1_000_000_000);
        ForkJoinTask<Long> forkJoinTask = forkJoinPool.submit(sumRecTask);
        System.out.println(forkJoinTask.get());
        long endMilli = System.currentTimeMillis();
        System.out.println("endMilli - startMilli = " + (endMilli - startMilli));
    }


    static class SumRecTask extends RecursiveTask<Long> {

        long left;
        long right;
        long diff = 1_000;

        public SumRecTask(long left, long right) {
            this.left = left;
            this.right = right;
        }

        @Override
        protected Long compute() {
            if (right - left <= diff) {
                long sum = 0L;
                for (long i = left; i <= right; i++) {
                    sum += i;
                }
                return sum;
            } else {
                long mid = (right + left) / 2 ;
                RecursiveTask<Long> sumRecTaskLeft = new SumRecTask(left, mid);
                // 拆分任务，把任务压入线程队列
                sumRecTaskLeft.fork();
                RecursiveTask<Long> sumRecTaskRight = new SumRecTask(mid + 1, right);
                sumRecTaskRight.fork();
                return sumRecTaskLeft.join() + sumRecTaskRight.join();
            }
        }
    }

}
